package com.luohoufa.ms.order.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

@Service
public class RedisLock {

    public static final String SCRIPT_REDIS_UNLOCK = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 该加锁方法仅针对单实例 Redis 可实现分布式加锁
     * 对于 Redis 集群则无法使用
     *
     * 支持重复，线程安全
     *
     * @param lockKey 加锁键
     * @param clientId 加锁客户端唯一标识
     * @param expirationTime 锁过期时间（单位：秒）
     * @return
     */
    public Boolean tryLock(String lockKey, String clientId, long expirationTime) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
            Boolean lockStat = redisConnection.set(lockKey.getBytes(Charset.forName("UTF-8")), clientId.getBytes(Charset.forName("UTF-8")),
                    Expiration.from(expirationTime, TimeUnit.SECONDS), RedisStringCommands.SetOption.SET_IF_ABSENT);
            return lockStat;
        });
    }

    /**
     * 释放锁
     * @param lockKey
     * @param clientId
     * @return
     */
    public Boolean releaseLock(String lockKey, String clientId) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
            Boolean lockStat = redisConnection.eval(SCRIPT_REDIS_UNLOCK.getBytes(), ReturnType.BOOLEAN, 1,
                    lockKey.getBytes(Charset.forName("UTF-8")), clientId.getBytes(Charset.forName("UTF-8")));
            return lockStat;
        });
    }

}
